/*
 * Title:        CloudScheduler Toolkit
 * Description:  a Toolkit for Modeling and Simulation of Job Scheduling and Resource Provisioning in Cloud System
 * Licence:      GPL - http://www.gnu.org/copyleft/gpl.html
 * Author:       Fuhui Wu
 *
 * Copyright (c) 2013-2014, The National University of Defense Technology, China
 */

package org.nudt.jCloud.evaluation;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import org.nudt.jCloud.simulation.SIMTag;
import org.nudt.jCloud.workload.Job;
import org.nudt.jCloud.workload.LogicalJob;
import org.nudt.jCloud.workload.Workload;

public class Evaluation {
	
	public static void avgWaitTime(String simName, String userName){
		File jobFile = new File("Log/"+simName+"/"+userName+"_Job");
		try {
			if(jobFile.exists()==false){
				throw new FileNotFoundException("no such job log file.");
			}else{
				Map<Integer, Tuple> jobStates = new HashMap<Integer, Tuple>();
				BufferedReader br = new BufferedReader(new FileReader(jobFile));
				String line = br.readLine();;
				while(line != null){
					String[] fields = line.split("\t");
					int jobId = Integer.parseInt(fields[1]);
					int op = Integer.parseInt(fields[2]);
					if(jobStates.containsKey(jobId)){
						if(op == SIMTag.XJOB_SUBMIT){
							jobStates.get(jobId).setSubmit(Double.parseDouble(fields[0]));
						}else if(op == SIMTag.XJOB_FINISH){
							jobStates.get(jobId).setFinish(Double.parseDouble(fields[0]));
						}
					}else{
						Tuple jobState = new Tuple();
						if(op == SIMTag.XJOB_SUBMIT){
							jobState.setSubmit(Double.parseDouble(fields[0]));
						}else if(op == SIMTag.XJOB_FINISH){
							jobState.setFinish(Double.parseDouble(fields[0]));
						}
						jobStates.put(jobId, jobState);
					}
					line = br.readLine();
				}
				br.close();
				int count = 0;
				double TWT = 0;
				for(Integer jobId : jobStates.keySet()){
					if(jobStates.get(jobId).getFinish()>jobStates.get(jobId).getSubmit()){
						TWT += jobStates.get(jobId).getFinish()-jobStates.get(jobId).getSubmit();
						count += 1;
					}
				}
				if(count >0){
					System.out.println(TWT/count);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}		
	}	
	
	public static void avgWeightedWaitTime(String simName, String userName){
		File taskFile = new File("Log/"+simName+"/"+userName+"_Task");
		try {
			if(taskFile.exists()==false){
				throw new FileNotFoundException("no such task log file.");
			}else{
				Map<String, Tuple> taskStates = 
						new HashMap<String, Tuple>();
				BufferedReader br = new BufferedReader(new FileReader(taskFile));
				String line = br.readLine();
				while(line != null){
					String[] fields = line.split("\t");
					String id = fields[1];
					double timestamp = Double.parseDouble(fields[0]);
					int state = Integer.parseInt(fields[2]);
					if(state!=SIMTag.TASK_SUBMIT&& state!=SIMTag.TASK_FINISH){
						line = br.readLine();
						continue;
					}else{
						if(taskStates.containsKey(id)){
							if(state == SIMTag.TASK_SUBMIT){
								taskStates.get(id).setSubmit(timestamp);
							}else{
								taskStates.get(id).setFinish(timestamp);
							}
						}else{
							Tuple taskState = new Tuple();
							if(state == SIMTag.TASK_SUBMIT){
								taskState.setSubmit(timestamp);
							}else{
								taskState.setFinish(timestamp);
							}
							taskStates.put(id, taskState);
						}
					}
					line = br.readLine();
				}
				br.close();
				int count = 0;
				double TWWT = 0;
				for(String id : taskStates.keySet()){
					if(taskStates.get(id).getFinish()>taskStates.get(id).getSubmit()){
						TWWT += taskStates.get(id).getFinish()- taskStates.get(id).getSubmit();
						count += 1;
					}
				}
				if(count >0){
					System.out.println(TWWT/count);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}		
	}
	
	public static void slotHour(String simName, String userBroker){
		double slotHour = 0;
		File taskFile = new File("Log/"+simName+"/"+userBroker+"_Frwk");
		try {
			if(taskFile.exists()==false){
				throw new FileNotFoundException("no such task log file.");
			}else{
				double lastT = 0;
				double currentT = 0;
				int slotNum = 0;
				BufferedReader br = new BufferedReader(new FileReader(taskFile));
				String line = br.readLine();
				String[] tempFields = line.split(";");
				lastT = Double.parseDouble(tempFields[0]);
				slotNum = Integer.parseInt(tempFields[7]);
				line = br.readLine();
				while(line != null){
					String[] fields = line.split(";");
					currentT = Double.parseDouble(fields[0]);
					slotHour += (currentT-lastT)*slotNum;
					lastT = currentT;
					slotNum = Integer.parseInt(fields[7]);
					line = br.readLine();
				}
				br.close();
				System.out.println(slotHour/3600);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}		
	}
	
	public static void slotShareDistribution(String simName, String userBroker){
		File taskFile = new File("Log/"+simName+"/"+userBroker+"_Frwk");
		SortedMap<Double, Integer> busySlotNumSet = new TreeMap<Double, Integer>();
		SortedMap<Double, Integer> freeSlotNumSet = new TreeMap<Double, Integer>();
		SortedMap<Double, Integer> totalSlotNumSet = new TreeMap<Double, Integer>();
		try {
			if(taskFile.exists()==false){
				throw new FileNotFoundException("no such task log file.");
			}else{
				BufferedReader br = new BufferedReader(new FileReader(taskFile));
				String line = br.readLine();
				while(line != null){
					String[] fields = line.split(";");
					int freeNum = 0;
					int busyNum = 0;
					if(fields[1].equals("")==false){
						String[] freeField = fields[1].split("\t");
						freeNum = Integer.parseInt(freeField[1]);
					}
					if(fields[2].equals("")==false){
						String[] busyField = fields[2].split("\t");
						busyNum = Integer.parseInt(busyField[1]);
					}
					freeSlotNumSet.put(Double.parseDouble(fields[0]), freeNum);
					busySlotNumSet.put(Double.parseDouble(fields[0]), busyNum);
					totalSlotNumSet.put(Double.parseDouble(fields[0]), Integer.parseInt(fields[3]));
					line = br.readLine();
				}
				br.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		double cumT = 0;
		int cumTotalNum = 0;
		int cumBusyNum = 0;
		int cumFreeNum = 0;
		int splitSize = totalSlotNumSet.size()/100;
		int count = 0;
		for(Double timestamp : totalSlotNumSet.keySet()){
			cumT += timestamp;
			cumTotalNum += totalSlotNumSet.get(timestamp);
			cumBusyNum += busySlotNumSet.get(timestamp);
			cumFreeNum += freeSlotNumSet.get(timestamp);
			count ++;
			if(count == splitSize){
				System.out.println(cumT/splitSize+"\t"+cumFreeNum/splitSize+"\t"+
						cumBusyNum/splitSize+"\t"+cumTotalNum/splitSize);
				cumT = 0;
				cumTotalNum = 0;
				cumBusyNum = 0;
				cumFreeNum = 0;
				count = 0;
			}
		}
	}
	
	public static void jobSizeDistribution(Workload wl){
		SortedMap<Double, Integer> jobSize = new TreeMap<Double, Integer>();
		int totalCount = wl.size();
		System.out.println("total size: "+totalCount);
		int splitSize = totalCount/100;
		int count = 0;
		int cumulateSize = 0;
		double startT = 0;
		double finishT = 0;
		double curT = 0;
		for(LogicalJob xJob : wl.getLogicalJobList()){
			int size = 0;
			for(Job job : xJob.getJobs()){
				size += job.size();
			}
			cumulateSize += size;
			count ++;
			if(count==splitSize){
				finishT = xJob.getArrivalTime();
				curT = (startT+finishT)/2;
				jobSize.put(curT, cumulateSize/splitSize);
				cumulateSize = 0;
				startT = finishT;
				count = 0;
			}
		}
		for(Double time : jobSize.keySet()){
			System.out.println(""+time+"\t"+jobSize.get(time));
		}
	}

	public static void wlSize(Workload wl){
		int size = 0;
		for(LogicalJob logicalJob : wl.getLogicalJobList()){
			for(Job job : logicalJob.getJobs()){
				size += job.size();
			}
		}
		System.out.println(size);
	}
	
	public static void localityCount(String simName, String user){
		int locality = 0;
		File taskFile = new File("Log/"+simName+"/"+user+"_Task");
		try {
			if(taskFile.exists()==false){
				locality = 0;
			}else{
				BufferedReader br = new BufferedReader(new FileReader(taskFile));
				String line = br.readLine();
				while(line != null){
					String[] fields = line.split("\t");
					if(Integer.parseInt(fields[2])==SIMTag.TASK_FINISH && 
							Integer.parseInt(fields[4])==1){
						locality+=1;
					}
					line = br.readLine();
				}
				br.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println(locality);
	}
	
	public static void concurrentFailureCount(String simName, String userBroker){
		int failureCount = 0;
		File taskFile = new File("Log/"+simName+"/"+userBroker+"_concurrentFailure");
		try {
			if(taskFile.exists()==false){
				failureCount = 0;
			}else{
				BufferedReader br = new BufferedReader(new FileReader(taskFile));
				String line = br.readLine();
				while(line != null){
					String[] fields = line.split("\t");
					failureCount += Integer.parseInt(fields[1]);
					line = br.readLine();
				}
				br.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println(failureCount);
	}
	
	public static void jobSchedulerBusyTime(String simName, String userBroker){
		int scheduleTime = 0;
		double lastTime = 0;
		File taskFile = new File("Log/"+simName+"/"+userBroker+"_concurrentFailure");
		try {
			if(taskFile.exists()==false){
				System.out.println(0);
				return;
			}else{
				BufferedReader br = new BufferedReader(new FileReader(taskFile));
				String line = br.readLine();
				while(line != null){
					String[] fields = line.split("\t");
					scheduleTime += Integer.parseInt(fields[1]);
					lastTime = Double.parseDouble(fields[0]);
					line = br.readLine();
				}
				br.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println(scheduleTime/lastTime);
	}
	
	
}
